/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package prostagra;

import java.awt.Image;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import obiekty.Mur;
import obiekty.ObiektRuchomy;
import obiekty.ObiektStaly;
import utils.Vector2D;

/**
 *
 * @author m
 */
public class Mapa
{
    
    
    private List<Mur> listaMurow;
    private List<ObiektStaly> obiektyStale;
    private List<ObiektRuchomy> listaInnych;
    private ObiektRuchomy gracz;
    private Image background = null;
    private static Mapa instance;
    private int szerokoscPlanszy, wysokoscPlanszy;


    private Mapa()
    {
        //instance = this;
        obiektyStale = Collections.synchronizedList(new LinkedList<ObiektStaly>());
        listaInnych = Collections.synchronizedList(new LinkedList<ObiektRuchomy>());
        listaMurow = Collections.synchronizedList(new LinkedList<Mur>());
    }
    
    
    /**
     * Przerabia punkt pobrany najprawdopodobniej z kliknięcia myszą na punkt
     * w przestrzeni planszy gry - punkt ten jest zależny od położenia gracza. Gracz jest
     * zawsze ustawiany w środku okna. Wyjątkiem od tej reguły jest zbliżenie się gracza
     * do granic mapy, na tyle, aby nie było możliwe przesunięcie mapy w ten sposób, aby gracz
     * był po środku okna i aby całe okno było wypełnione mapą - pozycja X gracza jest mniejsza niż 
     * połowa szerokości okna -> analogicznie pozycja Y 
     * @param punkt punkt w okienku gry
     * @param screenWidth szerokość okna
     * @param screenHeight wysokość okna
     * @return punkt w przestrzeni planszy gry
     */
    public Vector2D wezPrawdziwaPozycje(Vector2D punkt, int screenWidth, int screenHeight)
    {
        int offsetX = 0;
        int offsetY = 0;
        

        if (gracz.getPozycja().x - screenWidth / 2 > 0)
        {
            offsetX = (int) gracz.getPozycja().x - screenWidth / 2;
            if (offsetX > szerokoscPlanszy - screenWidth)
            {
                offsetX = szerokoscPlanszy - screenWidth;
            }
        }
        if (gracz.getPozycja().y - screenHeight / 2 > 0)
        {
            offsetY = (int) gracz.getPozycja().y - screenHeight / 2;
            if (offsetY > wysokoscPlanszy - screenHeight)
            {
                offsetY = wysokoscPlanszy - screenHeight;
            }
        }
        
        return new Vector2D(offsetX, offsetY).add(punkt);
    }

    /**
     * Zwraca iterator po obiektach stałych (nie poruszających się)
     * @return iterator po obiektach stałych
     */
    public List<ObiektStaly> getObiektyStale()
    {
        return obiektyStale;
    }

    /**
     * dodaje do mapy obiekt stały (nie poruszający się)
     * @param obiektStaly obiekt stały do dodania
     */
    public void addObiektStaly(ObiektStaly obiektStaly)
    {
        synchronized(obiektyStale)
        {
            obiektyStale.add(obiektStaly);
        }
    }

    
    /**
     * usuwa z mapy obiekt stały (nie poruszający się) 
     * @param obiektStaly obiekt stały do usunięcia
     */
    public void removeObiektStaly(ObiektStaly obiektStaly)
    {
        synchronized(obiektyStale)
        {
            obiektyStale.remove(obiektStaly);
        }
    }
    
    /**
     * Zwraca iterator po murach
     * @return iterator po murach
     */
    public List<Mur> getMury()
    {
        return listaMurow;
    }

    /**
     * dodaje do mapy mur
     * @param mur mur do dodania
     */
    public void addMur(Mur mur)
    {
        synchronized(listaMurow)
        {
            listaMurow.add(mur);
        }
    }

    
    /**
     * usuwa z mapy mur
     * @param mur mur do usunięcia
     */
    public void removeMur(Mur mur)
    {
        synchronized(listaMurow)
        {
            listaMurow.remove(mur);
        }
    }

    /**
     * pobiera referencję do obiektu gracza
     * @return obiekt gracza
     */
    public ObiektRuchomy getGracz()
    {
        return gracz;
    }

    /**
     * Tworzy gracza
     * @param gracz Gracz - stwór, którym kierujemy
     */
    public void setGracz(ObiektRuchomy gracz)
    {
        this.gracz = gracz;
    }

    /**
     * Dodaje do mapy obiekt ruchomy (poruszający się, ale inny od gracza)
     * @param inny obiekt ruchomy do dodania do mapy
     */
    public void addObiektRuchomy(ObiektRuchomy inny)
    {
        synchronized(listaInnych)
        {
            listaInnych.add(inny);
        }
    }

    /**
     * Usuwa z mapy obiekt ruchomy (poruszający się, ale inny od gracza)
     * @param inny obiekt ruchomy do usunięcia
     */
    public void removeObiektRuchomy(ObiektRuchomy inny)
    {
        synchronized(listaInnych)
        {
            listaInnych.remove(inny);
        }
    }

    
    /**
     * pobiera z mapy iterator po obiektach ruchomych (poruszających się, ale innych od gracza)
     * @return
     */
    public List<ObiektRuchomy> getObiektyRuchome()
    {
        return listaInnych;
    }
    
    
    /**
     * Pobiera szerokość mapy gry. Poza tę szerokość użytkownik nie będzie mógł się przemieścić.
     * @return szerokość mapy
     */
    public int getSzerokoscPlanszy()
    {
        return szerokoscPlanszy;
    }

    /**
     * Ustawia szerokość mapy gry. Poza tę szerokość użytkownik nie będzie mógł się przemieścić.
     * @param szerokoscPlanszy szerokość mapy
     */
    public void setSzerokoscPlanszy(int szerokoscPlanszy)
    {
        this.szerokoscPlanszy = szerokoscPlanszy;
    }

    
    /**
     * Pobiera wysokość mapy gry. Poza tę wysokość użytkownik nie będzie mógł się przemieścić.
     * @return wysokość mapy
     */
    public int getWysokoscPlanszy()
    {
        return wysokoscPlanszy;
    }

    /**
     * Ustawia wysokość mapy gry. Poza tę szerokość użytkownik nie będzie mógł się przemieścić.
     * @param wysokoscPlanszy
     */
    public void setWysokoscPlanszy(int wysokoscPlanszy)
    {
        this.wysokoscPlanszy = wysokoscPlanszy;
    }

    /**
     * Ustawia tło świata gry.
     * @param background tło świata gry.
     */
    public void setBackground(Image background)
    {
        this.background = background;
    }

    /**
     * Pobiera tło świata gry.
     * @return tło świata gry.
     */
    public Image getBackground()
    {
        return background;
    }

    
    /**
     * Pobiera instancję mapy -> w całej grze jest tylko jeden obiekt typu Mapa!
     * @return obiekt mapy gry
     */
    public static Mapa getInstance()
    {
        if (instance == null)
        {
            instance = new Mapa();
        }
        return instance;
    }
}
